using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Threading;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Server;
using TXLooker.Common;
using TXLooker.Common.Core;

namespace TXLooker.Core
{
    /// <summary>
    /// Contains Common Server Structures
    /// </summary>
    internal class TeamFoundationDataProvider : SelfUpdater
    {
        #region ITeamFoundationDataProvider Members

        public IEnumerable<ServerProvider> Servers
        {
            get 
            {
                lock( this.m_serverMAP )
                {
                    foreach( ServerProvider item in this.m_serverMAP.Values )
                        yield return item;
                }
            }
        }
        private Dictionary<Uri, ServerProvider> m_serverMAP = new Dictionary<Uri, ServerProvider>();

        public ServerProvider GetServerProvider( string serverUri )
        {
            return this.GetServerProvider( new Uri(serverUri) );
        }
        public ServerProvider GetServerProvider( Uri serverUri )
        {
            ServerProvider server = null;

            lock( this.m_serverMAP )
            {
                if( this.m_serverMAP.ContainsKey(serverUri) )
                    server = this.m_serverMAP[serverUri];
            }

            return server;
        }

        protected override void UpdateData()
        {
            foreach( IServerProvider item in this.Servers )
            {
                try
                {
                    item.Update();
                }
                catch( Exception ex )
                {
                    Debug.WriteLine( ex.ToString() );
                }
            }
        }

        #region event NewServers

        public event TFEventHandler<IEnumerable<ServerProvider>> NewServers
        {
            add { lock( this.m_syncNewServers ) { this.m_OnNewServersEH += value; } }
            remove { lock( this.m_syncNewServers ) { this.m_OnNewServersEH -= value; } }
        }
        private TFEventHandler<IEnumerable<ServerProvider>> m_OnNewServersEH = null;
        private readonly object m_syncNewServers = new object();

        private void RaiseNewServers(IEnumerable<ServerProvider> servers)
        {
            CommonGlobal.RaiseEventHandler( this.m_OnNewServersEH, new object[] { this, servers }, m_syncNewServers );
        }

        #endregion event NewServers

        #region event PreRemoveServers

        public event TFEventHandler<IEnumerable<ServerProvider>> PreRemoveServers
        {
            add    { lock( this.m_syncPreRemoveServers ) { this.m_OnPreRemoveServersEH += value; } }
            remove { lock( this.m_syncPreRemoveServers ) { this.m_OnPreRemoveServersEH -= value; } }
        }
        private TFEventHandler<IEnumerable<ServerProvider>> m_OnPreRemoveServersEH = null;
        private readonly object m_syncPreRemoveServers = new object();

        private void RaisePreRemoveServers(IEnumerable<ServerProvider> servers)
        {
            CommonGlobal.RaiseEventHandler( this.m_OnPreRemoveServersEH, new object[] { this, servers }, m_syncPreRemoveServers );
        }

        #endregion event PreRemoveServers

        #endregion ITeamFoundationDataProvider

        private RunWorkerCompletedEventHandler workCompletedCallback;

        public void AddServersAsync(IEnumerable<ServerConfigItem> items, RunWorkerCompletedEventHandler workCompletedHandler)
        {
            workCompletedCallback = workCompletedHandler;
            BackgroundWorker bw=  new BackgroundWorker();
            bw.DoWork += bw_DoWork;
            bw.RunWorkerCompleted += bw_RunWorkerCompleted;
            bw.RunWorkerAsync(items);
        }

        void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (workCompletedCallback != null)
                workCompletedCallback(this, e);
        }

        void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            IEnumerable<ServerConfigItem> items = e.Argument as IEnumerable<ServerConfigItem>;
            if (items != null)
                AddServers(items);
        }

        public IEnumerable<ServerProvider> AddServers( IEnumerable<ServerConfigItem> items )
        {
            List<ServerProvider> servers = new List<ServerProvider>();

            lock( this.m_serverMAP )
            {
                foreach( ServerConfigItem item in items )
                {
                    Uri uri = new Uri(item.ServerURI);

                    if( this.m_serverMAP.ContainsKey(uri) )
                        continue;

                    ServerProvider server = new ServerProvider(uri);
                    server.UseProjectFilter = true;
                    server.SetProcessProjectList( item.ProjectURIs );

                    //register servers
                    this.m_serverMAP.Add(uri, server);

                    servers.Add(server);
                }
            }

            if( servers.Count != 0 )
            {
                //Notify clients ( they make subscribers for server state changes )
                try
                {
                    this.RaiseNewServers( servers );
                }
                catch( Exception ex )
                { 
                    Debug.WriteLine( ex.ToString() );
                }

                //Load or Update Server Data
                foreach( ServerProvider item in servers )
                {
                    try
                    {
                        item.Update();
                    }
                    catch( System.Exception ex )
                    {
                        Debug.WriteLine( ex.ToString() );
                    }
                }
            }

            return servers;
        }
        public ServerProvider AddServer( ServerConfigItem item )
        {
            IEnumerable<ServerProvider> items = this.AddServers( new ServerConfigItem[] { item } );
            if( items == null ) return null;

            List<ServerProvider> servers = new List<ServerProvider>( items );
            return ( servers.Count > 0 ) ? servers[0] : null;
        }

        public void RemoveServers( IEnumerable<Uri> uries )
        {
            List<ServerProvider> servers = new List<ServerProvider>();

            lock( this.m_serverMAP )
            {
                foreach( Uri uri in uries )
                    if( this.m_serverMAP.ContainsKey(uri) )  servers.Add(this.m_serverMAP[uri]);
            }

            if( servers.Count != 0 )
            {
                try
                { 
                    this.RaisePreRemoveServers( servers ); 
                }
                catch( Exception ex )
                { 
                    Debug.WriteLine( ex.ToString() ); 
                }

                lock( this.m_serverMAP )
                {
                    foreach( ServerProvider item in servers )
                        this.m_serverMAP.Remove( item.ServerUri );
                }
            }
        }
        public void RemoveServers( IEnumerable<ServerProvider> servers )
        {
            List<Uri> uries = new List<Uri>();

            foreach( ServerProvider item in servers )
                uries.Add( item.ServerUri );

            if( uries.Count != 0 ) this.RemoveServers( uries );
        }
        public void RemoveServer( Uri serverUri )
        {
            this.RemoveServers( new Uri[] { serverUri } );
        }
        public void RemoveServer( string serverUri )
        {
            this.RemoveServer( new Uri( serverUri ) );
        }
        public void RemoveServer( ServerProvider server )
        {
            this.RemoveServer( server.ServerUri );
        }



        public static ICommonStructureService GetCommonServerStructure( TeamFoundationServer server )
        {
            return ServerProvider.GetCommonServerStructure( server );
        }
        public static ICommonStructureService GetCommonServerStructure( string uri )
        {
            return ServerProvider.GetCommonServerStructure( uri );
        }
        public static ICommonStructureService GetCommonServerStructure( Uri uri )
        {
            return ServerProvider.GetCommonServerStructure( uri );
        }
        public static IEnumerable<ProjectInfo> GetProjects( string serverUri )
        {
            ICommonStructureService service = GetCommonServerStructure( serverUri );
            if( service == null ) return null;

            List<ProjectInfo> projects = new List<ProjectInfo>();

            foreach( ProjectInfo item in service.ListAllProjects() )
            {
                switch( item.Status )
                {
                    case ProjectState.New:
                    case ProjectState.WellFormed:
                        projects.Add( item );
                        break;
                    case ProjectState.Deleting:
                        break;
                    default:
                        throw new NotImplementedException();
                }
            }

            projects.Sort(
                delegate (ProjectInfo x, ProjectInfo y)
                    {
                        return string.CompareOrdinal(x.Name, y.Name);
                    }
            );

            return projects;
        }
        public static IEnumerable<ProjectInfo> GetProjects( Uri serverUri )
        {
            return GetProjects( serverUri.ToString() );
        }
        public static IEnumerable<ProjectInfo> GetProjects( TeamFoundationServer server )
        {
            return GetProjects( server.Uri );
        }
    }
}
